﻿
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;

public struct _conn_par
{
    public string ip;
    public int Search_port;
    public int Control_port;
    public int Image_port;
}



namespace Pitaya_IDE
{

    public delegate void UP_DATA_CALLBACK();
    
    public class Pitaya_Device 
    {
        public string Device_type;  //设备类型
        public string Device_name;  //设备名字
        public _conn_par Conn_par;  //ip与端口
        public string sig_intensity;   //信号强度
        public int conn_sta = 0;   //连接状态  0未连接  1连接
        public int choose_sta = 0; //选择状态  0未选择  1选择
        private Socket clientSocket;
        private byte[] tmp_data = new byte[1024*64];
        private int mark = 0;
        public int connecting = 0;
        private int Tick_timeout = 0;
        private Thread conn_th = null, Receive_th = null, Tick_th = null;
        byte[] tmp_mark = new byte[32];
        public string Pitaya_ID;
        Panel panel = null;
        Form1 form1;
        UP_DATA_CALLBACK update_callback=null;
        private static Pitaya_Device mythis;
        public string drive_Name = "Z";

        public Pitaya_Device(Form1 _form1)
        {
            Random ran = new Random();
            mythis = this;
            form1 = _form1;

            if (mark == 0)
            {
                mark = ran.Next(1000,9999);
            }
            Set_data(tmp_mark, 0x00020005, mark);
        }

        public Pitaya_Device(Form1 _form1,UP_DATA_CALLBACK callback)
        {
            Random ran = new Random();
            mythis = this;
            form1 = _form1;

            if (mark == 0)
            {
                mark = ran.Next(1000, 9999);
            }

            update_callback = callback;
            Set_data(tmp_mark, 0x00020005, mark);
        }

        public Pitaya_Device(Form1 _form1,UP_DATA_CALLBACK callback,Panel _panel)
        {
            Random ran = new Random();
            mythis = this;
            form1 = _form1;

            if (mark == 0)
            {
                mark = ran.Next(1000, 9999);
            }

            update_callback = callback;
            Set_data(tmp_mark, 0x00020005, mark);

            panel = _panel;
        }

        public Pitaya_Device(Form1 _form1,string device_type, string device_name, _conn_par conn_par, string sig_intensity)
        {
            Device_type = device_type;
            Device_name = device_name;
            Conn_par = conn_par;
            this.sig_intensity = sig_intensity;

            Random ran = new Random();
            mythis = this;
            form1 = _form1;

            if (mark == 0)
            {
                mark = ran.Next(1000, 9999);
            }
            Set_data(tmp_mark, 0x00020005, mark);
        }

        public void Pitaya_conn()
        {
            if (connecting == 0)
            {
                conn_th = new Thread(Conn_th);
                conn_th.Start();
            }
        }

        List<byte[]> SendNodelist= new List<byte[]>();
        private Thread do_Send_th;
        static object lockObj = new object();

        int addcnt2 = 0;
        public void Send_cmd(byte[] src)
        {
            byte[] dst = new byte[src.Length + 1];

            src.CopyTo(dst, 0);

            lock (lockObj)
            {
                SendNodelist.Add(dst);
            }

            FileStream fs = null;

            while (fs == null)
            {
                try
                {
                    fs = File.OpenWrite(path);
                }
                catch (IOException)
                {
                    Thread.Sleep(10);
                }
            }

            Encoding encoder = Encoding.UTF8;

            fs.Position = fs.Length;

            uint[] par = Get_par(dst);
            byte[] bytes;
            if (dst.Length > 32)
            {
                byte[] bytes2 = new byte[dst.Length - 32];

                for (int i = 0; i < dst.Length - 32; i++)
                {
                    bytes2[i] = dst[32 + i];
                }

                bytes = encoder.GetBytes("-" + SendNodelist.Count + "->第" + addcnt2 + "次发送数据，par[]=" +
                    par[0] + "," + par[1] + "," + par[2] + "," + par[3] + "," +
                    par[4] + "," + par[5] + "," + par[6] + "," + par[7] +
                    Encoding.UTF8.GetString(bytes2) + "\r\n");
            }
            else
            {
                bytes = encoder.GetBytes("-" + SendNodelist.Count + "->第" + addcnt2 + "次发送数据，par[]=" +
                    par[0] + "," + par[1] + "," + par[2] + "," + par[3] + "," +
                    par[4] + "," + par[5] + "," + par[6] + "," + par[7] + "\r\n");
            }
            addcnt2++;

            fs.Write(bytes, 0, bytes.Length);

            fs.Flush();
            fs.Close();
        }

        int addcnt5 = 0;
        public void Send_cmd_(byte[] src)
        {
            
            byte[] dst = new byte[src.Length + 1];

            src.CopyTo(dst, 0);

            lock (lockObj)
            {
                SendNodelist.Add(dst);
            }

            FileStream fs = null;

            while (fs == null)
            {
                try
                {
                    fs = File.OpenWrite(path);
                }
                catch (IOException)
                {
                    Thread.Sleep(10);
                }
            }

            Encoding encoder = Encoding.UTF8;

            fs.Position = fs.Length;

            uint[] par = Get_par(dst);
            byte[] bytes;
            if (dst.Length > 32)
            {
                byte[] bytes2 = new byte[dst.Length - 32];

                for (int i = 0; i < dst.Length - 32; i++)
                {
                    bytes2[i] = dst[32 + i];
                }

                bytes = encoder.GetBytes("*" + SendNodelist.Count + "*>第" + addcnt5 + "次发送数据，par[]=" +
                    par[0] + "," + par[1] + "," + par[2] + "," + par[3] + "," +
                    par[4] + "," + par[5] + "," + par[6] + "," + par[7] +
                    Encoding.UTF8.GetString(bytes2) + "\r\n");
            }
            else
            {
                bytes = encoder.GetBytes("*" + SendNodelist.Count + "*>第" + addcnt5 + "次发送数据，par[]=" +
                    par[0] + "," + par[1] + "," + par[2] + "," + par[3] + "," +
                    par[4] + "," + par[5] + "," + par[6] + "," + par[7] + "\r\n");
            }
            addcnt5++;

            fs.Write(bytes, 0, bytes.Length);

            fs.Flush();
            fs.Close();
        }

        string path = @"C:\Users\Administrator\Desktop\data.txt";
        private void do_SendCmd()
        {
            while (true)
            {
                Thread.Sleep(10);
                if (SendNodelist.Count > 0)
                {
                    byte[] tmp = SendNodelist[0];
                    SendNodelist.Remove(tmp);
                    try
                    {
                        lock (lockObj)
                        {
                            clientSocket.Send(tmp);
                        }
                    }
                    catch (SocketException)
                    {
                        clientSocket.Close();
                        Disconnect();
                        SendNodelist.Clear();
                        return;
                    }

                    FileStream fs = null;

                    while (fs == null)
                    {
                        try
                        {
                            fs = File.OpenWrite(path);
                        }
                        catch (IOException)
                        {
                            Thread.Sleep(10);
                        }
                    }
                    Encoding encoder = Encoding.UTF8;

                    fs.Position = fs.Length;

                    uint[] par = Get_par(tmp);
                    byte[] bytes;
                    if (tmp.Length > 32)
                    {
                        byte[] bytes2 = new byte[tmp.Length - 32];

                        for (int i = 0; i < tmp.Length - 32; i++)
                        {
                            bytes2[i] = tmp[32 + i];
                        }

                        bytes = encoder.GetBytes("FFF" + SendNodelist.Count + "*>第" + addcnt5 + "次发送数据，par[]=" +
                            par[0] + "," + par[1] + "," + par[2] + "," + par[3] + "," +
                            par[4] + "," + par[5] + "," + par[6] + "," + par[7] +
                            Encoding.UTF8.GetString(bytes2) + "\r\n");
                    }
                    else
                    {
                        bytes = encoder.GetBytes("FFF" + SendNodelist.Count + "*>第" + addcnt5 + "次发送数据，par[]=" +
                            par[0] + "," + par[1] + "," + par[2] + "," + par[3] + "," +
                            par[4] + "," + par[5] + "," + par[6] + "," + par[7] + "\r\n");
                    }
                    addcnt5++;

                    fs.Write(bytes, 0, bytes.Length);

                    fs.Flush();
                    fs.Close();
                }
                
                if (conn_sta == 0)
                {
                    return;
                }
            }
        }

        private void Conn_th()
        {
            if (conn_sta == 1) return;

            if (connecting == 1)
            {
                return;
            }
            connecting = 1;

            if (update_callback != null)
            {
                update_callback();
            }

            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IAsyncResult connResult = clientSocket.BeginConnect(Conn_par.ip, Conn_par.Control_port,null,null);
            connResult.AsyncWaitHandle.WaitOne(2000,true);
            if (!connResult.IsCompleted)
            {
                connecting = 0;
                Disconnect();
                return;
            }

            try
            {
                clientSocket.Send(tmp_mark);
            }
            catch (ObjectDisposedException)
            {
                connecting = 0;
                Disconnect();
                return;
            }
            

            Tick_timeout = 15;
            connecting = 0;
            conn_sta = 1;

            Tick_th = new Thread(Tick);
            Tick_th.Start();

            Receive_th = new Thread(Do_Receive);
            Receive_th.Start();

            do_Send_th = new Thread(do_SendCmd);
            do_Send_th.Start();

            Process p = new Process();
            bool SMB_sta = true;

            /*检查windows samba协议是否有打开*/
            p.StartInfo.UseShellExecute = false;    //是否使用操作系统shell启动
            p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
            p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
            p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
            p.StartInfo.CreateNoWindow = true;//不显示程序窗口
            p.StartInfo.FileName = "cmd.exe";//Samba  net use Z: \\192.168.2.112\share
            p.Start();//启动程序

            p.StandardInput.WriteLine("dism /online /Get-Features > tmp.txt" + "&exit");
            p.StandardInput.AutoFlush = true;

            p.WaitForExit();//等待程序执行完退出进程
            p.Close();

            StreamReader sr = new StreamReader("tmp.txt");

            for (string output; (output = sr.ReadLine()) != null;)
            {
                if (Regex.IsMatch(output, @"SMB1Protocol-Client"))
                {
                    int count = 0;
                    string str = sr.ReadLine();
                    foreach (char chr in str)
                    {
                        count += chr;
                    }
                    if (count == 395656) //已启用
                    {
                        SMB_sta = true;
                    }
                    else
                    {
                        SMB_sta = false;
                    }
                }
            }
            
            sr.Close();
            File.Delete("tmp.txt");

            if(SMB_sta)
            {
                //挂载之前要查看一下  有没有Z这个驱动器了！！！！！
                DriveInfo[] drives = DriveInfo.GetDrives();
                for (int i = drives.Length - 1; i > 0; i--)
                {
                    DriveInfo drive = drives[i];
                    if (drive.Name.Equals(drive_Name + ":\\"))
                    {
                        char[] outchar = new char[1];
                        outchar[0] = (char)(drive_Name[0] - 1);
                        drive_Name = new string(outchar);
                    }
                    else break;
                }

                /*挂载samba*/
                p.Start();//启动程序

                //向cmd窗口发送输入信息//
                p.StandardInput.WriteLine("net use " + drive_Name + ": \\\\" + Conn_par.ip + "\\share &explorer  " + drive_Name + ":\\ &exit");
                p.StandardInput.AutoFlush = true;

                p.WaitForExit();//等待程序执行完退出进程
                p.Close();
            }
            else
            {
                MessageBox.Show("检测到您系统还未启动samba1协议，已配置启动\n下一个弹窗的‘是’是重启，‘否’是稍后重启!!", "需要重启计算机！", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
                
                //启动程序
                p.Start();
                //向cmd窗口发送输入信息
                p.StandardInput.WriteLine("start /w pkgmgr /iu:SMB1Protocol;SMB1Protocol-Client" + "&exit");
                p.StandardInput.AutoFlush = true;
                p.WaitForExit();//等待程序执行完退出进程
                p.Close();
                Environment.Exit(0);
            }
            
            if (update_callback != null)
            {
                update_callback();
            }
            //if (panel == null)
            //{
            //    Fsp = new File_sys(this,form1);
            //}
            //else
            //{
            //    Fsp = new File_sys(this, panel, form1);
            //}
        }

        private void Do_Receive()
        {
            int Length ;

            while (true)
            {
                try
                {
                    Length = clientSocket.Receive(tmp_data);
                }
                catch (SocketException)
                {
                    Disconnect();
                    return;
                }
                catch (ObjectDisposedException)
                {
                    Disconnect();
                    return;
                }
                Tick_timeout = 15;
                conn_sta = 1;
                CallBack(Length);
            }
        }

        private void CallBack(int Length)
        {
            uint[] par;
            par = Get_par(tmp_data);

            switch (par[0])
            {
                case 0x00000000: break; //Tick
                case 0x00000001: break; //run_py
                case 0x00000002: break; //stop_py
                case 0x00000003: break; //pdb_py 

                case 0x00010001: break; //ls
                case 0x00010002: break; //mkdir
                case 0x00010003: break; //touch
                case 0x00010004: break; //read
                case 0x00010005: break; //write
                case 0x00010006: break; //remove
                case 0x00010007: break; //rename
                case 0x00010008: break; //ls_ret //已弃用
                case 0x00010009: break;
                case 0x0001000a: break;

                case 0x00020000: break; //print
                case 0x00020001: break; //sacnf
                case 0x00020002: err_printf(par,tmp_data); break; //err_print
                case 0x00020003: break; //runerr_print
                case 0x00020004: break; //py_stop
                case 0x00020005: break; //mark_information

                case 0x00030000: break; //settime

                case 0x00040000://文件监视相关
                case 0x00040001:
                case 0x00040002://已全部弃用
                case 0x00040003:
                case 0x00040006: break;

                case 0xffffffff: break; //
            }
        }

        /**
         * 下一步实现远程启动python脚本，
         * 但是得先弄好启动与调试界面
         */

        /// <summary>
        /// 错误打印
        /// </summary>
        /// <param name="par"></param>
        /// <param name="tmp_dat"></param>

        private void err_printf(uint[] par, byte[] tmp_dat)
        {
            byte[] _print = new byte[par[2] + 16];

            for (int i = 0; i < par[2]; i++)
            {
                _print[i] = tmp_dat[32 + i];
            }
            _print[par[2]] = 0;

            //Form1.form_main.textBox1.Text += Encoding.ASCII.GetString(_print) + "\r\n";
        }

        public void Disconnect()  // 断开连接
        {
            clientSocket.Close();
            conn_sta = 0;
            Tick_timeout = 0;

            {
                Process p = new Process();
                p.StartInfo.UseShellExecute = false;    //是否使用操作系统shell启动
                p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
                p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
                p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
                p.StartInfo.CreateNoWindow = true;//不显示程序窗口
                p.StartInfo.FileName = "cmd.exe";//Samba  net use Z: \\192.168.2.112\work
                p.Start();//启动程序

                //向cmd窗口发送输入信息
                p.StandardInput.WriteLine("net use " + drive_Name + ": /delete" + "&exit");

                p.StandardInput.AutoFlush = true;

                p.WaitForExit();//等待程序执行完退出进程
                p.Close();
            }
            //MessageBox.Show("连接断开");

            if (update_callback != null)
            {
                update_callback();
            }
            
            if (form1.fileMunePanel.Show1)
            {
                form1.fileMunePanel.Show1 = false;
                form1.Rd_window();
            }

            form1.UpdateDrawFlag = 1;
        }

        private void Tick()
        {
            int cnt = 0, time_cnt = 0;
            byte[] tmp = new byte[32];

            for (int i = 0; i < 32; i++)
            {
                tmp[i] = 0;
            }

            while (true)
            {
                Thread.Sleep(200);
                if (conn_sta == 0) return;
                cnt++;
                if (cnt >= 5)
                {
                    time_cnt++;
                    if (time_cnt >= 20)  //20秒发送一次时间
                    {
                        Set_data(tmp, 0, 1, DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day,
                                    DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second);
                        time_cnt = 0;
                    }
                    else
                    {
                        Set_data(tmp, 0, 0);  //平常发送滴答信号
                    }
                    try
                    {
                        clientSocket.Send(tmp);
                    }
                    catch (ObjectDisposedException)
                    {
                        Tick_timeout = 0;
                    }
                    cnt = 0;
                }

                if (Tick_timeout > 0)
                {
                    Tick_timeout--;
                }
                else
                {
                    bool flag = false;
                    //心跳数据包超时  尝试重连
                    Disconnect();
                    for (int i = 0; i < 3; i++)
                    { 
                        if (Reconnect_th() != 0)
                        {
                            flag = true;
                            break;
                        }
                    }

                    if (flag == false)
                    {
                        return;
                    }
                }
            }
        }

        private int Reconnect_th()
        {
            if (conn_sta == 1) return 1;

            if (connecting == 1)
            {
                return 0;
            }
            connecting = 1;
            
            if (update_callback != null)
            {
                update_callback();
            }

            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IAsyncResult connResult = clientSocket.BeginConnect(Conn_par.ip, Conn_par.Control_port, null, null);
            connResult.AsyncWaitHandle.WaitOne(2000, true);
            if (!connResult.IsCompleted)
            {
                connecting = 0;
                return 0;
            }

            Tick_timeout = 15;
            try
            {
                clientSocket.Send(tmp_mark);
            }
            catch (ObjectDisposedException)
            { }
            connecting = 0;
            conn_sta = 1;

            Receive_th = new Thread(Do_Receive);
            Receive_th.Start();


            if (update_callback != null)
            {
                update_callback();
            }
            return 1;
        }

        public void Set_update_callback(UP_DATA_CALLBACK callback)
        {
            update_callback = callback;
        }

        private uint[] Get_par(byte[] src)
        {
            uint[] par = new uint[8];
            int offset;

            for (int i=0;i<8;i++)
            {
                offset = i * 4;
                par[i] = (uint)(((src[offset + 0] & 0xFF) << 0)
                             | ((src[offset + 1] & 0xFF) << 8)
                             | ((src[offset + 2] & 0xFF) << 16)
                             | ((src[offset + 3] & 0xFF) << 24));
            }

            return par;
        }

        private static void IntToBytes(byte[] src, int value, int offset)
        {
            src[3 + offset] = (byte)((value >> 24) & 0xFF);
            src[2 + offset] = (byte)((value >> 16) & 0xFF);
            src[1 + offset] = (byte)((value >> 8) & 0xFF);
            src[0 + offset] = (byte)((value >> 0) & 0xFF);
        }

        //设置指令
        public static void Set_data(byte[] src, int CMD, int par1, int par2, int par3, int par4, int par5, int par6, int par7)
        {
            IntToBytes(src, CMD, 0);
            IntToBytes(src, par1, 4);
            IntToBytes(src, par2, 8);
            IntToBytes(src, par3, 12);
            IntToBytes(src, par4, 16);
            IntToBytes(src, par5, 20);
            IntToBytes(src, par6, 24);
            IntToBytes(src, par7, 28);
        }

        public static void Set_data(byte[] src, int CMD, int par1, int par2, int par3, int par4, int par5, int par6)
        {
            IntToBytes(src, CMD, 0);
            IntToBytes(src, par1, 4);
            IntToBytes(src, par2, 8);
            IntToBytes(src, par3, 12);
            IntToBytes(src, par4, 16);
            IntToBytes(src, par5, 20);
            IntToBytes(src, par6, 24);
        }

        public static void Set_data(byte[] src, int CMD, int par1, int par2, int par3, int par4, int par5)
        {
            IntToBytes(src, CMD, 0);
            IntToBytes(src, par1, 4);
            IntToBytes(src, par2, 8);
            IntToBytes(src, par3, 12);
            IntToBytes(src, par4, 16);
            IntToBytes(src, par5, 20);
        }

        public static void Set_data(byte[] src, int CMD, int par1, int par2, int par3, int par4)
        {
            IntToBytes(src, CMD, 0);
            IntToBytes(src, par1, 4);
            IntToBytes(src, par2, 8);
            IntToBytes(src, par3, 12);
            IntToBytes(src, par4, 16);
        }

        public static void Set_data(byte[] src, int CMD, int par1, int par2, int par3)
        {
            IntToBytes(src, CMD, 0);
            IntToBytes(src, par1, 4);
            IntToBytes(src, par2, 8);
            IntToBytes(src, par3, 12);
        }

        public static void Set_data(byte[] src, int CMD, int par1, int par2)
        {
            IntToBytes(src, CMD, 0);
            IntToBytes(src, par1, 4);
            IntToBytes(src, par2, 8);
        }

        public static void Set_data(byte[] src, int CMD, int par1)
        {
            IntToBytes(src, CMD, 0);
            IntToBytes(src, par1, 4);
        }
        
        public static void Set_data(byte[] src, int[] par)
        {
            for (int i = 0; i < 8; i++)
            {
                IntToBytes(src, par[i], 4 * i);
            }
        }

        public static void Set_data(byte[] src, int CMD)
        {
            IntToBytes(src, CMD, 0);
        }

        public static void Set32Data(byte[] src, string str)
        {
            int i = 0;
            foreach (byte dat in str)
            {
                src[i + 32] = dat;
                i++;
            }
        }

        public static void SetStringData(byte[] src, string str,int offset)
        {
            int i = 0;
            foreach (byte dat in str)
            {
                src[i + offset] = dat;
                i++;
            }
        }

        public static void SetStringData(byte[] src, byte[] str, int offset)
        {
            int i = 0;
            foreach (byte dat in str)
            {
                src[i + offset] = dat;
                i++;
            }
        }
    }

}